<?php
/*
 * @Description : 限流工具类(令牌桶)
 * @filename    : CurrentLimitingUtil.php
 * @author      : liuqingwei
 * @date        : 2018.09.07
 *
 * @Copyright (c) 2017 liuqingwei
 * vim set ts=4
 */
class CurrentLimitingUtil
{
    
    const QUEUE         = 'xxx'; //令牌队列
    const USERLIMITKEY  = 'aaa'; //用户限制key
    
    private $redis;
    private $max;

    /***
     * 初始化
     */
    public function __construct()
    {
        $redis_conf  = Conf::getConf("MODE/redis");
        $this->redis = Redis::getService($redis_conf);
    }
    
    /**
     * 添加令牌
     * 
     * @param int $num 加入令牌数(每秒,详看定时脚本)
     * 
     * @return
     */
    public function add($num)
    {
        $current_num = intval($this->redis->llen(self::QUEUE),NULL);
        
        $this->max = $this->getMax();
        
        $num = ($this->max >= ($current_num + $num) ? $num : ($this->max - $current_num));

        if ($num > 0)
        {
            $token = array_fill(0,$num - 1,1);
            $this->redis->lpush(self::QUEUE, ...$token);
        }
    }
    
    /**
     * 获取令牌
     */
    public function get()
    {
        return $this->redis->rpop(self::QUEUE)? true : false;
    }
    
    /**
     * 重置令牌
     */
    public function reset()
    {
        $this->max = $this->getMax();
        $this->redis->del(self::QUEUE);
        $this->add($this->max);
    }
    
    /***
     * 获取最大令牌
     */
    public function getMax()
    {
        $num = $this->redis->get(Shopping_Define_Const::SECKILL_LIMIT_MAX);
        $num = $num ? $num : 2000;
        return $num;
    }
    
    /**
     * 获取速率
     */
    public function getRate()
    {
        $num = $this->redis->get(Shopping_Define_Const::SECKILL_LIMIT_RATE);
        $num = $num ? $num : 2000;
        return $num;
    }


    /**
     * 接口防刷限制
     * 
     * @param string $function  接口名称
     * @param string $open_id   用户微信id
     * 
     * @return int
     */
    public function userLimit($function,$open_id)
    {
        $key   = self::USERLIMITKEY.':'.$function.':'.$open_id;
        $limit = $this->redis->get($key) ? $this->redis->get($key) : 0;
        if ($limit >= 30)
        {
            if ($limit >= 100)
            {
                $this->redis->setex($key,300,++$limit);
            } 
            else
            {
                $this->redis->setex($key,10,++$limit);
            }
            
            return $limit;
        }
        
        $this->redis->setex($key,5,++$limit);
        return 0;     
    }
}
